package com.yami.shop.app.controller;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yami.shop.app.config.PushMessageUtil;
import com.yami.shop.app.utils.HttpResult;
import com.yami.shop.bean.model.OldUser;
import com.yami.shop.bean.model.ShopDetail;
import com.yami.shop.bean.model.User;
import com.yami.shop.bean.model.UserDeposit;
import com.yami.shop.bean.param.DepositMoneyParam;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.security.util.SecurityUtils;
import com.yami.shop.service.*;
import io.swagger.annotations.Api;
import ma.glasnost.orika.impl.util.StringUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

@RestController
@RequestMapping("/app/depositMoney")
@Api(tags = "充值接口")
@Component
@PropertySource("classpath:application.yml")
@ConfigurationProperties(prefix = "app")
public class DepositMoneyController {

    private  static String authorization;

    @Value("${appId}")
    private String appId;

    @Value("${appKey}")
    private  String appKey;

    @Value("${merchantCode}")
    private String merchantCode; //商户号

    @Value("${terminalCode}")
    private String terminalCode; //终端号

    @Value("${payUrl}")
    private String payUrl;//支付接口

    @Autowired
    private UserService userService;
    @Autowired
    private UserDepositService userDepositService;
    @Autowired
    private Snowflake snowflake;
    @Autowired
    private UmsPayInformationService umsPayInformationService;
    @Autowired
    private OldUserService oldUserService;
    @Autowired
    private ShopDetailService shopDetailService;

    /*充值记录查询**/
    @PostMapping("/selectDepositMoneyRecord")
    public HttpResult selectDepositMoneyRecord(@RequestBody DepositMoneyParam depositMoneyParam, PageParam<UserDeposit> page)
    {
        if(depositMoneyParam.getCurrent()!=null){
            page.setCurrent(depositMoneyParam.getCurrent());
        }
        if(depositMoneyParam.getSize()!=null){
            page.setSize(depositMoneyParam.getSize());
        }
        User user = new User();
        String userId=null;
        if(StringUtils.isNotEmpty(depositMoneyParam.getMobile())){
            user = userService.selectUserByPhoneOne(depositMoneyParam.getMobile());//根据手机号码获取会员
            userId=user.getUserId();//获取会员id
        }
        IPage<UserDeposit> records = userDepositService.page(page,
                new LambdaQueryWrapper<UserDeposit>()
                        .eq(UserDeposit::getShopId,SecurityUtils.getSysUser().getShopId())
                        .eq(userId!=null,UserDeposit::getUserId,userId)
                        .eq(StringUtils.isNotEmpty(depositMoneyParam.getOrderNumber()),UserDeposit::getOrderNumber,depositMoneyParam.getOrderNumber())
                        .ge(depositMoneyParam.getStartTime()!=null,UserDeposit::getCreateTime,depositMoneyParam.getStartTime())
                        .le(depositMoneyParam.getEndTime()!=null,UserDeposit::getCreateTime,depositMoneyParam.getEndTime())
                        .orderByDesc(UserDeposit::getCreateTime));
        return HttpResult.success(records);
    }

    /**
     * 充值金额
     */
    @PostMapping("/insertDepositMoneyRecord")
    public HttpResult insertDepositMoneyRecord(@RequestBody DepositMoneyParam depositMoneyParam){
        //根据手机号码获取会员
        User user = userService.selectUserByPhoneOne(depositMoneyParam.getMobile());
        UserDeposit userDeposit = new UserDeposit();
        //雪花算法生成一个订单号
        String orderNumber = String.valueOf(snowflake.nextId());
        //赠送比例(10%),计算赠送的金额
        Double preSentMoney = Arith.mul(depositMoneyParam.getDepositMoney(),new Double(0.1));
        if(user!=null) {
            userDeposit.setOrderNumber(orderNumber);
            userDeposit.setUserId(user.getUserId());
            userDeposit.setCashier(SecurityUtils.getSysUser().getUserId());
            userDeposit.setShopId(SecurityUtils.getSysUser().getShopId());
            userDeposit.setAmount(depositMoneyParam.getDepositMoney());
            userDeposit.setCreateTime(new Date());
            userDeposit.setStatus(2);
            userDeposit.setCid(depositMoneyParam.getCid());
            userDeposit.setEnterAccountStatus(2);
            userDeposit.setPresentMoney(new BigDecimal(preSentMoney));
            userDepositService.save(userDeposit);
        }
        return  HttpResult.success(orderNumber);
    }

    /**
     * 现金支付充值金额
     */
    @PostMapping("/depositMoneyByCash")
    public HttpResult depositMoneyByCash(@RequestBody DepositMoneyParam depositMoneyParam){
        UserDeposit userDeposit = userDepositService.getDepositMoneyByOrderNumber(depositMoneyParam.getOrderNumber());
        User user = null;
        Long shopId = SecurityUtils.getSysUser().getShopId();
        if(userDeposit!=null){
           user = userDepositService.depositMoneyByCash(userDeposit.getDepositId());
           String userId = user.getUserId();
           OldUser oldUser = oldUserService.getOldUserByShopId(userId,shopId);
            if(oldUser!=null){
                BigDecimal oldAccount = oldUser.getAccount();
                user.setOldAccount(oldAccount.doubleValue());
            }
        }
        return HttpResult.success(user);
    }

    /**
     * 银联支付充值金额
     */
    @PostMapping("/depositMoneyByUms")
    public HttpResult depositMoneyByUms(@RequestBody DepositMoneyParam depositMoneyParam){
        UserDeposit userDeposit = userDepositService.getDepositMoneyByOrderNumber(depositMoneyParam.getOrderNumber());
        String orderNumber=null;
        double payMoney = 0.00;
        User user =null;
        if(userDeposit!=null){
             orderNumber = userDeposit.getOrderNumber();
             payMoney = userDeposit.getAmount();
        }
        try {
            Double amount = Arith.mul(payMoney,100);
            System.out.println("充值金额   "+amount);
            String result = payV2(orderNumber,depositMoneyParam.getPayCode(), Arith.mul(payMoney,100));
            System.out.println("扫码充值返回结果"+result);
            //支付成功
            user =  umsPayInformationService.dealPayByUms(result,orderNumber,userDeposit.getDepositId());

            //支付成功,向设备返回支付成功的消息
            String cid = userDeposit.getCid();
            try {
                PushMessageUtil.pushToSingleByCid(cid,orderNumber);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return  HttpResult.success(user);
    }

    /**
     * 进行pos通支付操作,整理参数
     * 接口地址:
     * 测试环境：http://58.247.0.18:29015/v2/poslink/transaction/pay
     * 生产环境：https://api-mop.chinaums.com/v2/poslink/transaction/pay
     */
    public  String payV2(String orderNumber,String payCode,Double payMoney) throws Exception {
        ShopDetail shopDetail =shopDetailService.getShopDetailByShopId(SecurityUtils.getSysUser().getShopId());
        /* post参数,格式:JSON */
        JSONObject body = new JSONObject();
        //body.put("merchantCode", shopDetail.getMerchantCode());   // 商户号
        //body.put("terminalCode", shopDetail.getTerminalCode());   // 终端号
        body.put("merchantCode",merchantCode);
        body.put("terminalCode",terminalCode);
        body.put("transactionAmount", payMoney);  // 交易金额,遇到传goods的情况,得算出来
        body.put("transactionCurrencyCode", "156"); // 交易币种
        body.put("merchantOrderId", orderNumber);  // 商户订单号,自定义
        body.put("merchantRemark", "商户备注"); // 商户备注
        body.put("payMode", "CODE_SCAN");    // 支付方式:    E_CASH(电子现金) SOUNDWAVE(声波) NFC(NFC) CODE_SCAN(扫码) MANUAL(手输)
        body.put("payCode", payCode); // 这里需要真实的支付码eg:286656579659199426
        body.put("srcReserved", "商户冗余信息|aabb|cc");  // 商户冗余信息
        body.put("orderDesc", "账单描述");
        //String url = "http://58.247.0.18:29015/v2/poslink/transaction/pay";
        String send = send(payUrl, body.toString());
        System.out.println("send  result"+send);
        return send;
    }



    /**
     * 发送请求
     *
     * @param url    eg:http://58.247.0.18:29015/v2/poslink/transaction/pay
     * @param entity eg:{"merchantCode":"123456789900081","terminalCode":"00810001","transactionAmount":1,"transactionCurrencyCode":"156","merchantOrderId":"201905211550526234902343","merchantRemark":"商户备注","payMode":"CODE_SCAN","payCode":"285059979526414634"}
     * @return
     * @throws Exception
     */
    public  String send(String url, String entity) throws Exception {
        authorization = getOpenBodySig(appId, appKey, entity);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Authorization", authorization);
        StringEntity se = new StringEntity(entity, "UTF-8");
        se.setContentType("application/json");
        httpPost.setEntity(se);
        CloseableHttpResponse response = httpClient.execute(httpPost);
        HttpEntity entity1 = response.getEntity();
        String resStr = null;
        if (entity1 != null) {
            resStr = EntityUtils.toString(entity1, "UTF-8");
        }
        httpClient.close();
        response.close();
        return resStr;
    }


    /**
     * open-body-sig方式获取到Authorization 的值
     *
     * @param appId  f0ec96ad2c3848b5b810e7aadf369e2f
     * @param appKey 775481e2556e4564985f5439a5e6a277
     * @param body   json字符串 String body = "{\"merchantCode\":\"123456789900081\",\"terminalCode\":\"00810001\",\"merchantOrderId\":\"20123333644493200\",\"transactionAmount\":\"1\",\"merchantRemark\":\"测试\",\"payMode\":\"CODE_SCAN\",\"payCode\":\"285668667587422761\",\"transactionCurrencyCode\":\"156\"}";
     * @return
     * @throws Exception
     */
    public static String getOpenBodySig(String appId, String appKey, String body) throws Exception {
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());   // eg:20190227113148
        String nonce = UUID.randomUUID().toString().replace("-", ""); // eg:be46cd581c9f46ecbd71b9858311ea12
        byte[] data = body.getBytes("UTF-8");
        System.out.println("data:\n" + body);
        InputStream is = new ByteArrayInputStream(data);
        String bodyDigest = testSHA256(is);
        System.out.println("bodyDigest:\n" + bodyDigest);
        String str1_C = appId + timestamp + nonce + bodyDigest;
        byte[] localSignature = hmacSHA256(str1_C.getBytes(), appKey.getBytes());
        String localSignatureStr = Base64.encodeBase64String(localSignature);   // Signature
        System.out.println("Authorization:\n" + "OPEN-BODY-SIG AppId=" + "\"" + appId + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce=" + "\"" + nonce + "\"" + ", Signature=" + "\"" + localSignatureStr + "\"\n");
        return ("OPEN-BODY-SIG AppId=" + "\"" + appId + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce=" + "\"" + nonce + "\"" + ", Signature=" + "\"" + localSignatureStr + "\"");
    }

    /**
     * 进行加密
     *
     * @param is
     * @return 加密后的结果
     */
    private static String testSHA256(InputStream is) {
        try {
            return DigestUtils.sha256Hex(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     *
     *
     * @param data
     * @param key
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public static byte[] hmacSHA256(byte[] data, byte[] key) throws NoSuchAlgorithmException, InvalidKeyException {
        String algorithm = "HmacSHA256";
        Mac mac = Mac.getInstance(algorithm);
        mac.init(new SecretKeySpec(key, algorithm));
        return mac.doFinal(data);
    }


}
